package net.zhuike.novel.app.ui.utils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class REUtil {
	private static final String[] EMPTY = new String[0];
	
	public static String match(String pattern, String target) {
		return match(pattern, target, true);
	}

	public static String match(String pattern, String target, boolean caseInsensitive) {
		Pattern p = createPattern(pattern, caseInsensitive);
		Matcher matcher = p.matcher(target);
		if (matcher.find()) {
			return matcher.group();
		} else {
			return "";
		}
	}

	public static String[] matchs(String pattern, String target) {
		return matchs(pattern, target, true);
	}

	public static String[] matchs(String pattern, String target, boolean caseInsensitive) {
		Pattern p = createPattern(pattern, caseInsensitive);
		Matcher matcher = p.matcher(target);
		List<String> contents = new ArrayList<String>();
		while (matcher.find()) {
			contents.add(matcher.group());
		}
		return contents.toArray(EMPTY);
	}

	public static String group(String pattern, String target, int index) {
		return group(pattern, target, true, index);
	}
	public static String group(String pattern, String target, boolean caseInsensitive, int index) {
		Pattern p = createPattern(pattern, caseInsensitive);
		Matcher matcher = p.matcher(target);
		if (matcher.find()) {
			try {
				return matcher.group(index);
			} catch (IndexOutOfBoundsException err) {
				throw new IllegalArgumentException(String.format("pattern [%s]'s index[%s] is out of bound.", pattern, index));
			}
		} else {
			return "";
		}
	}

	public static String[] groups(String pattern, String target) {
		return groups(pattern, target, true);
	}
	public static String[] groups(String pattern, String target, boolean caseInsensitive) {
		Pattern p = createPattern(pattern, caseInsensitive);
		Matcher matcher = p.matcher(target);
		if (matcher.find()) {
			int groupCount = matcher.groupCount();
			String[] parts = new String[groupCount];
			for (int i = 1; i <= groupCount; i++) {
				parts[i - 1] = matcher.group(i);
			}
			return parts;
		} else {
			return EMPTY;
		}
	}
	
	private static Map<String, Pattern> patterns = new FIFOMap<String, Pattern>(100);
	public static Pattern createPattern(String patternValue, boolean caseInsensitive) {
		Pattern pattern = patterns.get(patternValue);
		if (pattern == null) {
			synchronized (patterns) {
				pattern = patterns.get(patternValue);
				if (pattern == null) {
					pattern = Pattern.compile(patternValue, caseInsensitive ? Pattern.CASE_INSENSITIVE : 0);
					patterns.put(patternValue, pattern);
				}
			}
		}
		
		return pattern;
	}
	
	public static String replace(String source, String regex, String target) {
		if (target.indexOf('$') == -1) {
			return source.replaceAll(regex, target);
		}
		
		StringBuilder buffer = new StringBuilder(source);
		String[] matchedValues = REUtil.matchs(regex, source);
		int start = 0;
		for (String matchedValue : matchedValues) {
			String[] groups = REUtil.groups(regex, matchedValue);
			start = buffer.indexOf(matchedValue, start);
			String newTarget = target;
			for (int i = 0; i < groups.length; i++) {
				newTarget = newTarget.replaceAll(String.format("\\$%s", i+1), groups[i]);
			}
			buffer.replace(start, start + matchedValue.length(), newTarget);
			start += newTarget.length();
		}
		return buffer.toString();
	}
}
